package testing;

import game.BGBoard;
import java.util.ArrayList;
import ai.AI_Controller;
import ai.ANN;
import ai.PubevalAI;
import ai.RandomAI;

public class ANNTrainController {
	AI_Controller pubEvil = new AI_Controller(new PubevalAI()); 
	AI_Controller randomGimp = new AI_Controller(new RandomAI()); //random moves for lower bound, we must beat this at least
	AI_Controller ANNai;
	AI_Controller whitePlayer;
	AI_Controller blackPlayer;
	BGBoard board = new BGBoard();
	int generations = 100000;
	int training = 15;
	int benchMatches = 150;
	
	public void train(){
		System.out.println("Number of benchmarked matches: " + Integer.toString(benchMatches));
		boolean white;
		AI_Controller Rocky = new AI_Controller(new ANN());
		Rocky.getANN().randomWeights();
		AI_Controller Challenger;
		int whiteWin = 0, blackWin = 0;
		
		for(int i = 0; i<generations;i++){
		System.out.println("Generation:" + Integer.toString(i));	
			//Benchmark phase!
			if(i%100 == 0){
				System.out.println("Benchmark Generation [" + Integer.toString(i) + "]");
				//Against random
				whitePlayer = randomGimp;
				blackPlayer = Rocky;
				whiteWin = 0;
				blackWin = 0;
				
				for(int bench = 0; bench < benchMatches ;bench++){
					white = play(whitePlayer, blackPlayer);
					if(white){
						whiteWin++;
					}else{
						blackWin++;
					}
				}
				
				System.out.print("randomGimp/ANN: ");
				System.out.println(Integer.toString(whiteWin)+ "/" 
						+ Integer.toString(blackWin) );
	
				//Against pubeval
				whitePlayer = pubEvil;
				blackPlayer = Rocky;
				whiteWin = 0;
				blackWin = 0;
				
				for(int bench = 0; bench < benchMatches ;bench++){
					white = play(whitePlayer, blackPlayer);
					if(white){
						whiteWin++;
					}else{
						blackWin++;
					}
				}
				
				System.out.print("PubEval/ANN: ");
				System.out.println(Integer.toString(whiteWin)+ "/" 
						+ Integer.toString(blackWin) );

			}

		
			//Training sequence
			//System.out.println("Training sequence");
			whitePlayer = new AI_Controller(Rocky.getANN().mutate());
			whiteWin = 0;
			blackWin = 0;
			for(int train = 0; train < training;train++){
				white = play(whitePlayer, blackPlayer);
				if(white){
					whiteWin++;
				}else{
					blackWin++;
				}
				if(whiteWin > training/2 || blackWin > training/2 ){
					train = training;
				}
			}
		
			if(whiteWin >= blackWin){ //challenger wins
				Rocky.getANN().adjust(whitePlayer.getANN());	
			}
		}
	}

	public void testmatch(){
		whitePlayer = randomGimp;
		blackPlayer = new AI_Controller(new ANN());
		int whiteWin = 0, blackWin = 0;
		
		for(int i = 0; i < 10;i++){
			boolean white;
			white = play(whitePlayer, blackPlayer);
			if(white){
				whiteWin++;
			}else{
				blackWin++;
			}
			
			
		}
		
		System.out.println("White player (" + whitePlayer.whatsUrName() +"): " + Integer.toString(whiteWin) + "\n");
		System.out.println("Black player (" + blackPlayer.whatsUrName() +"): " + Integer.toString(blackWin) + "\n");
	}
	
	/**
	 * plays one match between the players
	 * @param blackPlayer
	 * @param whitePlayer
	 * @return Returns true if white player wins
	 */
	public boolean play(AI_Controller whitePlayer, AI_Controller blackPlayer){
            board = new BGBoard();
            board.setPlayer_white(whitePlayer.whatsUrName());
            board.setPlayer_black(blackPlayer.whatsUrName());
            board.initializeBoard();
            // with turn
            while (true) {
                board.diceRoll();
                //printBoard();
                board.GetPossiblePositions();

                int nrOfMoves = 2;
                if (board.getDice()[0] == board.getDice()[1]) {
                    nrOfMoves = 4;
                }

                if (board.whosMove == BGBoard.WHITE) {
                    doMoves(board, whitePlayer, nrOfMoves);
                } else {
                    doMoves(board, blackPlayer, nrOfMoves);
                }

                // check if there is a winner
                //System.out.println(board);
                if (board.isReadyBlack() || board.isReadyWhite()) {
                    if (board.checkWinner()) {
                        //announceWinner(board.getWinner());
                        //System.out.println(board);
                        if (board.getWinner() == BGBoard.WHITE) {
                            return true;
                        } else {
                            return false;
                        }
                    }
                }

                board.changePlayer();
            }

        }



    public void testMutation(){
    	
    	ANN Rocky = new ANN();
    	ANN mutant;
    	double[][] input = new double[40][201];
    	double[] output = new double[40];
    	
    	//Rocky.setWeights(input, output);
    	mutant = Rocky.mutate();
    	
    	
    	
    }
		
	public void announceWinner(boolean winner) {
    System.out.println((winner) ? "White wins!" : "Black wins!");
	}
	
	
	
    private void doMoves(BGBoard board, AI_Controller ai, int nrOfMoves) {
        board.GetPossiblePositions();
        ArrayList<byte[]> moves = ai.makemoves((BGBoard) board.clone());
        for (int i = 0; i < nrOfMoves; i++) {
            if (moves.size() > i) {
                board.applyMove(moves.get(i)[0], moves.get(i)[1]);
            }
        }
    }

}
